﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Threading;

using ScriptCompiler2;
using System.CodeDom.Compiler;

namespace WindowsRemoteScripting.Action
{
    public class ExecuteScript : AbstractCommand
    {
        protected string m_sLastCompiledScript = string.Empty;

        protected CReflectiveEvaluator m_ReflectiveEvaluator = new CReflectiveEvaluator();

        public ExecuteScript()
        {
            m_ReflectiveEvaluator.CompilerError += new CompilerErrorEventHandler(a_CompilerError);
            m_ReflectiveEvaluator.CompilerSuccess += new EventHandler(a_CompilerSuccess);
            m_ReflectiveEvaluator.TypeCreationError += new TypeCreationErrorEventHandler(ReflectiveEvaluator_TypeCreationError);

            string sPath = Application.StartupPath + @"\RemoteScriptingLibrary.dll";
            m_ReflectiveEvaluator.AddUsing(sPath);
            m_ReflectiveEvaluator.AddUsing("System.Windows.Forms.dll");
            m_ReflectiveEvaluator.AddUsing("System.Drawing.dll");
            //m_ReflectiveEvaluator.AddUsing("System.IO
            //a.AddUsing("System.Runtime.Interopservices.dll");
        }

        void ReflectiveEvaluator_TypeCreationError(object sender, TypeCreationErrorEventArgs e)
        {
            throw new NotImplementedException();
        }

        void a_CompilerSuccess(object sender, EventArgs e)
        {
            Form1.m_Form.textBoxCompilerOutput.Invoke(new MethodInvoker(delegate() { Form1.m_Form.textBoxCompilerOutput.Text = "Successful compilation"; }));
        }

        void a_CompilerError(object sender, CompilerErrorEventArgs e)
        {
            GenerateCompilerErrorText(e);
        }

        private void GenerateCompilerErrorText(CompilerErrorEventArgs e)
        {
            string sOutput = string.Empty;
            foreach (CompilerError error in e.CompilerErrorCollection)
            {
                int nLineIndex = GetCorrectLineIndex();


                sOutput += string.Format("{0} {1} {2}", error.ErrorNumber, "Line: " + (error.Line - nLineIndex).ToString(), error.ErrorText);
            }
            Form1.m_Form.textBoxCompilerOutput.Invoke(new MethodInvoker(delegate() { Form1.m_Form.textBoxCompilerOutput.Text = sOutput; }));
            Form1.m_Form.textBoxCompilerOutput.Invoke(new MethodInvoker(delegate() { Form1.m_Form.textBoxCompilerOutput.Text += Environment.NewLine;}));
            Form1.m_Form.textBoxCompilerOutput.Invoke(new MethodInvoker(delegate() { Form1.m_Form.textBoxCompilerOutput.Text += Environment.NewLine;}));
            Form1.m_Form.textBoxCompilerOutput.Invoke(new MethodInvoker(delegate() { Form1.m_Form.textBoxCompilerOutput.Text += "--------------------"; }));
            Form1.m_Form.textBoxCompilerOutput.Invoke(new MethodInvoker(delegate() { Form1.m_Form.textBoxCompilerOutput.Text += m_sLastCompiledScript;}));
        }

        private static int GetCorrectLineIndex()
        {
            string sScript = ScriptTemplate.sScriptCompilerClass;
            List<string> aLine = new List<string>();
            aLine.AddRange(Regex.Split(sScript, Environment.NewLine));
            int nLineIndex = aLine.FindIndex(
                delegate(string _sText)
                {
                    return _sText.Contains("{0}");
                });
            return nLineIndex;
        }

        public override void Run(object sender, EventArgs e)
        {
            Form1.m_Form.textBoxCompilerOutput.Clear();
            NumberedTextBoxLib.NumberedTextBox richTextBox1 = Form1.m_Form.textBoxScript;

            string sScript = ParseScript(richTextBox1);
            m_sLastCompiledScript = sScript;

            try
            {
                Thread thread = new Thread(new ThreadStart(delegate() { m_ReflectiveEvaluator.Eval(sScript, "ScriptCompilerClass", "Test"); }));
                thread.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private static string ParseScript(NumberedTextBoxLib.NumberedTextBox richTextBox1)
        {
            string sScript = ScriptTemplate.sScriptCompilerClass;
            string sCommand = string.Format("{0}{1};", "Script.", richTextBox1, ";");

            string sOtherToken = "%|else|if|while|do|for|{|}|goto|var";

            string[] aOtherToken = Regex.Split(sOtherToken, @"\|");
            string sResult = string.Empty;
            foreach (string sLine in Form1.m_Form.textBoxScript.Lines)
            {
                if (string.IsNullOrEmpty(sLine))
                {
                    sResult += Environment.NewLine;
                    continue;
                }

                bool bReplaceLine = true;

                if (sLine.TrimStart(' ').StartsWith("/*"))
                {
                    sResult += sLine;
                    sResult += Environment.NewLine;
                    continue;
                }

                if (sLine.TrimStart(' ').StartsWith("//"))
                {
                    sResult += sLine;
                    sResult += Environment.NewLine;
                    continue;
                }

                if (sLine.TrimStart(' ').StartsWith("%"))
                {
                    sResult += sLine.TrimStart('%'); ;
                    sResult += Environment.NewLine;
                    continue;
                }

                //if (sLine.TrimStart(' ').StartsWith(""))
                //{
                //    bReplaceLine = false;
                //    sResult += sLine.TrimStart('%');
                //    sResult += Environment.NewLine;
                //    continue;
                //}

                foreach (string sToken in aOtherToken)
                {
                    if (sLine.TrimStart(' ').StartsWith(sToken))
                    {
                        sResult += sLine;
                        bReplaceLine = false;
                        sResult += Environment.NewLine;
                        break;
                    }
                }
                if (bReplaceLine)
                {
                    sResult += string.Format("Script.{0}{1}", sLine, ";") + Environment.NewLine;
                }
            }
            sCommand = sResult;
            sScript = sScript.Replace("{0}", sCommand);
            return sScript;
        }

        public string LastCompiledScript
        {
            get { return m_sLastCompiledScript; }
        }
    }
}
